import java.util.ArrayList;
import java.util.Collections;

import org.nlogo.headless.*;
import java.util.Random;

public class HillClimbing {

	public static String matString(int[] m) {
		return "[ " + m[0] + " " + m[1] + " " + m[2] + " " +
				+ m[3] + " " + m[4] + " " + m[5] + " " +
				+ m[6] + " " + m[7] + " " + m[8] + " ]";

	}

	public static int[] randomMat(int m) {
		int[] matrice = new int[9];
		Random r = new Random();
		int somme_m = m;
		int valeur_r = 0;
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 2 ; j++) {
				valeur_r = r.nextInt(somme_m);
				matrice[(i * 3) + j] = valeur_r;
				somme_m = somme_m - valeur_r;
			}
			matrice[(i * 3) + 2] = somme_m;
			somme_m = m;
		}
		return matrice;
	}

	/*
	 * ligne = [0 ... 2]
	 */
	public static int[] varie(int[] m, int delta, int ligne) {
		int[] res = m.clone();
		int newA1, newA2, newA3;
		if (ligne == 0) {
			newA1 = m[ligne * 3] + delta;
			if (newA1 < 0 || newA1 > 60) {
				return m;
			}
			newA2 = m[(ligne * 3) + 1] - (delta / 2);
			if (newA2 < 0 || newA2 > 60) {
				return m;
			}
			newA3 = m[(ligne * 3) + 2] - (delta / 2);
			if (newA3 < 0 || newA3 > 60) {
				return m;
			}
		}
		else {
			if (ligne == 1) {
				newA1 = m[ligne * 3] - (delta / 2);
				if (newA1 < 0 || newA1 > 60) {
					return m;
				}
				newA2 = m[(ligne * 3) + 1] + delta;
				if (newA2 < 0 || newA2 > 60) {
					return m;
				}
				newA3 = m[(ligne * 3) + 2] - (delta / 2);
				if (newA3 < 0 || newA3 > 60) {
					return m;
				}
			}
			else {
				newA1 = m[ligne * 3] - (delta / 2);
				if (newA1 < 0 || newA1 > 60) {
					return m;
				}
				newA2 = m[(ligne * 3) + 1] - (delta / 2);
				if (newA2 < 0 || newA2 > 60) {
					return m;
				}
				newA3 = m[(ligne * 3) + 2] + delta;
				if (newA3 < 0 || newA3 > 60) {
					return m;
				}
			}
		}
		
		res[ligne * 3] = newA1;
		res[(ligne * 3) + 1] = newA2;
		res[(ligne * 3) + 2] = newA3;
		return res;
	}

	public static void test() {

		ArrayList<Double> resultats = new ArrayList<Double>();
		HeadlessWorkspace ws = HeadlessWorkspace.newInstance();

		int nbIterations = 10;
		int resultat = 0;
		int nbNoeuds = 200;

		int[] matrice = randomMat(60);

		try {

			ws.open("projet.nlogo");
			ws.command("set n " + (nbNoeuds - 3));
			ws.command("set preferenceList " + matString(matrice));
			for (int i = 0; i < nbIterations; i++) {
				ws.command("runExperiences");
				resultats.add((Double)ws.report("listeResultats"));
			}
			Collections.sort(resultats);
			resultat = (resultats.get(resultats.size() / 2)).intValue();
			System.out.println( matString(matrice) + ": " + resultat + " infectés sur " + nbNoeuds);
			ws.dispose();
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}

	public static int mediane(HeadlessWorkspace ws, int nbNoeuds,int nbIterations, int[] matrice) {
		
		int resultat = -1;
		ArrayList<Integer> resultats = new ArrayList<Integer>();
		
		try {
			ws.command("set n " + (nbNoeuds - 3));
			ws.command("set preferenceList " + matString(matrice));
			for (int i = 0; i < nbIterations; i++) {
				ws.command("runExperiences");
				int res = ((Double)ws.report("listeResultats")).intValue();
				resultats.add(res);
			}
			Collections.sort(resultats);
			resultat = (resultats.get(resultats.size() / 2)).intValue();
			//System.out.println( matString(matrice) + ": " + resultat + " infectés sur " + nbNoeuds);
		}
		catch(Exception e) {
			e.printStackTrace();
		}
		return resultat;
	}
	
	
	public static void main(String[] args) {

		HeadlessWorkspace ws = HeadlessWorkspace.newInstance();
		try {
			ws.open("projet.nlogo");
		}
		catch(Exception e) {
			e.printStackTrace();
		}
		int DELTA = 2;
		int NB_NOEUDS = 500;
		int NB_ITER = 5;
		int[] matrice = randomMat(60);
		System.out.println("matrice de départ random:" + matString(matrice));
		int scoreDeReference = mediane(ws, NB_NOEUDS, NB_ITER, matrice);
		System.out.println("son score de référence:" + scoreDeReference);
		int newScore;
		int oldScore;
		int cnt = 1;
		
		do {
			oldScore = scoreDeReference;
			int[] voisin1 = varie(matrice, DELTA, 0);
			int[] voisin2 = varie(matrice, DELTA, 1);
			int[] voisin3 = varie(matrice, DELTA, 2);
			newScore = mediane(ws, NB_NOEUDS, NB_ITER, voisin1);
			System.out.println("score de voisin1: " + newScore + " ;matrice voisin1: " + matString(voisin1));
			if(newScore < scoreDeReference) {
				matrice = voisin1;
				scoreDeReference = newScore;
			}
			newScore = mediane(ws, NB_NOEUDS, NB_ITER, voisin2);
			System.out.println("score de voisin2: " + newScore + " ;matrice voisin2: " + matString(voisin2));
			if(newScore < scoreDeReference) {
				matrice = voisin2;
				scoreDeReference = newScore;
			}
			newScore = mediane(ws, NB_NOEUDS, NB_ITER, voisin3);
			System.out.println("score de voisin3: " + newScore + " ;matrice voisin3: " + matString(voisin3));
			if(newScore < scoreDeReference) {
				matrice = voisin3;
				scoreDeReference = newScore;
			}
			System.out.println("[" + cnt + "] ancien score: " + oldScore + ", nouveau score: " + scoreDeReference + " avec la matrice " + matString(matrice));
			cnt++;
		}
		while(scoreDeReference < oldScore);
		
		System.out.println("nombre de morts:" + scoreDeReference);
		
		try {
			ws.dispose();
		}
		catch(Exception e) {
			e.printStackTrace();
		}

	}



























}
